﻿// MediaInfo.cpp: implementation of the CMediaInfo class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MediaInfo.h"

#include <string>
#include <iostream>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define COUNTOF(a)			(sizeof(a)/sizeof(a[0]))
#define DOUBLE_MIN_LIMIT	(0.00001)

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMediaInfo::CMediaInfo()
{
}

CMediaInfo::CMediaInfo(LPCTSTR lpMediaInfoExe, LPCTSTR lpMediaInfoLongExe, LPCTSTR lpFFMpegExe, LPCTSTR lpFFMpegLongExe, LPCTSTR lpTempFolder, int m_iKeepTempFiles, BOOL m_bIgnoreUTC)
{
	this->initMediaInfo(lpMediaInfoExe, lpMediaInfoLongExe, lpFFMpegExe, lpFFMpegLongExe, lpTempFolder, m_iKeepTempFiles, m_bIgnoreUTC);
}

CMediaInfo::~CMediaInfo()
{
}

void CMediaInfo::initMediaInfo(LPCTSTR lpMediaInfoExe, LPCTSTR lpMediaInfoLongExe, LPCTSTR lpFFMpegExe, LPCTSTR lpFFMpegLongExe, LPCTSTR lpTempFolder, int m_iKeepTempFiles, BOOL m_bIgnoreUTC) {
	initValues();
	
	csMediaInfoExe = lpMediaInfoExe;
	csMediaInfoLongExe = lpMediaInfoLongExe;
	csFFMpegExe = lpFFMpegExe;
	csFFMpegLongExe = lpFFMpegLongExe;
	csTempFolder = lpTempFolder;
	iKeepTempFiles = m_iKeepTempFiles;
	bIgnoreUTC = m_bIgnoreUTC;
	
	tcFilename[0] = _TCHAR(0);
}

bool CMediaInfo::compareNGetValue(char *cBuf, const char *cName, CString &cs)
{
	if (!cBuf || !cName) return false;
	int len=strlen(cName);
	// 이름 다음에 공백 2개가 오는지도 확인 → 없앰(2013.7.28), 정확히 매치되는 내용만 비교
	if ((strncmp(cBuf, cName, len) == 0)/* && (strncmp(cBuf+len, "  ", 2) == 0)*/) {
		cs = cBuf;
		GetValue(cs);
		return true;
	}
	return false;
}

void CMediaInfo::GetMediaInfo(LPCTSTR lpFilename, bool processCover, LPCTSTR lpAudioCountry)
{
	// lpAudioCountry는 오디오 우선순위를 부여하기 위한 것
	// NULL이면 국가 코드의 우선순위 미부여
	// 그게 아니면 그 국가 코드가 최우선, 나머지는 ko-en-ja-de-fr-ru 순
	// 그 외의 국가를 우선으로 하려면 **
	// 오디오는 aac - dts - ac3 - mp2/3 - ogg
	// 우선순위는 큰 게 장땡 / ko 80, en 70, ja 60, de 50, fr 40, ru 30, **(else) 20 / 단, 일치하면 90
	// aac 6 - dts 5 - wav 4 - ac3 3 - mp2/3 2 - ogg 1
	
	initValues();


	CFileStatus status;
	CFile::GetStatus(lpFilename, status);
	fileTime = status.m_mtime;


	// Stream Order는 내부용(Stream Identifier)을 별도로 만든 뒤에 마지막에 다시 정리
	// Channel Count는 Original Channel Count와 별도로 추출되는 경우가 있는데,
	// 이 경우는 좀 주의해야 됨.
	// 진짜 채널 수는 Original Channel Count에 나오고, Channel Count에는 컨테이너가 잘못 리포트한 결과가 들어감
	int iVideoStreamID;
	int iAudioStreamID[MAXAUDSUBCOUNT];
	int iSubStreamID[MAXAUDSUBCOUNT];
	int iOriginalChannelCount[MAXAUDSUBCOUNT];

	iVideoStreamID = -1;
	for (int i=0; i<MAXAUDSUBCOUNT; i++) {
		iAudioStreamID[i] = iSubStreamID[i] = iOriginalChannelCount[i] = -1;
	}
	iMenuStreamOrder = -1;
	sfMenuFormat = SFMT_NONE;
	iMenuID = -1;

	_tcscpy_s(tcFilename, MAX_PATH, lpFilename);
	
	CRedirect *redir;
	
	CString csBatch;
	CSmallUtilz4iTrans::makeBatchFileName(csBatch, csTempFolder, _T("getinfo"));
	CString csMediaInfoResult = csTempFolder+_T("mediainfo.txt");
	csFFMpegResult = csTempFolder+_T("ffmpeg.txt");
	
	
	// 실제로 실행시키는 부분은 ~Dlg.cpp에서 차용
	
	if (csMediaInfoExe.Find(_TCHAR('\\'))<0) return;
	
	// MediaInfo용 Batch file 생성 (csBatch)

	LPCTSTR lpAppLong = static_cast<LPCTSTR>(csMediaInfoLongExe);
	LPCTSTR lpAppLongName = CSmallUtilz4iTrans::getAppNameOnly(lpAppLong);
	
	FILE *f;
	if (_tfopen_s(&f, csBatch, _T("wt")) || !f) return;;
	
	CString csParam;
	csParam.Format(_T("-f \"%s\" > \"%s\""), lpFilename, static_cast<LPCTSTR>(csMediaInfoResult));
	
	CString cs;
	cs.Format(_T("\"%s\" %s\n"), static_cast<LPCTSTR>(csMediaInfoExe), static_cast<LPCTSTR>(csParam));
	
	printfuni2ansi(f, static_cast<LPCTSTR>(cs));
	
	fclose(f);
	
	// 실행
	CStringArray csaAppNames;
	csaAppNames.Add(lpAppLongName);
	redir = new CRedirect(csBatch, csaAppNames, NULL, NULL);
	redir->Run();
	
	// Batch file 삭제
	if (iKeepTempFiles<2)
		CSmallUtilz4iTrans::DeleteSomeFile(csBatch, iKeepTempFiles==1);
	
	delete redir;
	redir = NULL;
	
	UINT size = CSmallUtilz4iTrans::GetFileSize(csMediaInfoResult);
	char cBuf[MAX_PATH];
	
	int iMode=0;	// 1: General 정보, 2: Video 정보, 3: Audio 개수, 4: Text 개수, 5: 챕터
	int iAudioPos, iSubPos;
	CString csOriginalFPS;

	if (_tfopen_s(&f, csMediaInfoResult, _T("rt")) || !f) return;
	while (size && !feof(f)) {
		if (fgets(cBuf, MAX_PATH, f) == NULL) break;
		if (iscntrl_char(cBuf[0])) {
			iMode = 0;
			continue;
		}
		
		if (!iMode) {
			static LPCSTR categories[] = {
				"General",	"Video",	"Audio",	"Text",	"Menu"
			};
			for (int i=0; i<COUNTOF(categories); i++) {
				if (strncmp(cBuf, categories[i], strlen(categories[i])) == 0) {
					iMode = i+1;
				}
			}
			switch (iMode) {
			case 3:
				iAudioCount++;
				if (iAudioCount>MAXAUDSUBCOUNT) iAudioCount=MAXAUDSUBCOUNT;
				iAudioPos = iAudioCount-1;

				break;

			case 4:
				iSubCount++;
				if (iSubCount>MAXAUDSUBCOUNT) iSubCount=MAXAUDSUBCOUNT;
				iSubPos = iSubCount-1;

				break;
			}

			continue;
		}
		
		switch (iMode) {
		case 0:
			continue;
			
		case 1:
			{
				static LPCSTR generalInfoNames[] = {
					"Duration  ",	"Cover_Data  ",	"Format  ",	"File size  ", "Overall bit rate  ", "Encoded date  "
				};
				enum GENERALINFO {
					NONE,	DURATION,	COVERDATA,	FORMAT,	FILESIZE, OVERALLBITRATE, ENCODEDDATE
				};
				static enum GENERALINFO generalInfos[] = {
					DURATION,	COVERDATA,	FORMAT,	FILESIZE, OVERALLBITRATE, ENCODEDDATE
				};

				GENERALINFO info = NONE;
				CString cs;
				for (int i=0; i<COUNTOF(generalInfos); i++) {
					if (compareNGetValue(cBuf, generalInfoNames[i], cs)) {
						info = generalInfos[i];
						break;
					}
				}

				switch (info) {
				case COVERDATA:
					if (processCover) {
						csCover = csTempFolder+_T("cover.temp");
						if (!base64Decode(cs, csCover)) csCover = _T("");
					}
					break;

				case FORMAT:
					{
						ffFileFormat = FFMT_UNKNOWN;
						
						static LPCTSTR fileformats0[] = {
							_T("AVI"),	_T("DivX"),		_T("Matroska"),		_T("Flash Video"),
							_T("OGG"),	_T("MPEG-4"),
							_T("CDXA/MPEG-PS"),	_T("MPEG-PS"),	_T("MPEG-TS"),	_T("BDAV"),
							_T("Windows Media"),	_T("ShockWave"),	_T("QuickTime"), _T("RealMedia")
						};
						
						static FileFormat fileformats1[] = {
							FFMT_AVI,	FFMT_DIVX,	FFMT_MKV,	FFMT_FLV,
							FFMT_OGG,	FFMT_MP4,
							FFMT_MPGPS,	FFMT_MPGPS,	FFMT_MPGTS,	FFMT_BLURAY,
							FFMT_WMV,	FFMT_SWF,	FFMT_QT,	FFMT_RM
						};
						
						for (int i=0; i<COUNTOF(fileformats0); i++) {
							if (cs.Compare(fileformats0[i]) == 0) ffFileFormat = fileformats1[i];
						}
						
						if (ffFileFormat == FFMT_UNKNOWN) {
							if (cs.Left(4).Compare(_T("MPEG")) == 0) ffFileFormat = FFMT_MPGPS;
							else if (cs.CompareNoCase(_T("WebM")) == 0) ffFileFormat = FFMT_WEBM;
							else if (cs.Left(9).CompareNoCase(_T("RealMedia")) == 0) ffFileFormat = FFMT_RM;
						}
					}
					break;

				case FILESIZE:
					{
						long long llRet = 0;
						bool bStop = false;
						
						for (int i=0; i<cs.GetLength(); i++) {
							TCHAR tc = cs.GetAt(i);
							if (!_istdigit(tc)) {
								bStop = true;
								break;
							}
							
							llRet = llRet*10 + (tc - _TCHAR('0'));
						}
						
						if (!bStop) iFileSizeInMB = int(llRet/1024/1024);
					}
					break;

				case OVERALLBITRATE:
					if (cs.Find(_TCHAR(' '))<0 && cs.Find(_TCHAR('p'))<0)
						iOverallBitRate = _ttoi(cs);
					break;

				case ENCODEDDATE:
					{
						bool bUTC = (cs.Left(4).CompareNoCase(_T("UTC "))==0) && !bIgnoreUTC;
						cs.TrimLeft(_T("UTC "));
						int p = cs.Find(_TCHAR('.'));
						if (p>=0) cs = cs.Left(p);

						COleDateTime otime;
						if (otime.ParseDateTime(cs)) {
							if (bUTC) {
								TIME_ZONE_INFORMATION timeZoneInformation;
								GetTimeZoneInformation(&timeZoneInformation);

								SYSTEMTIME timeUTC;
								otime.GetAsSystemTime(timeUTC);
								SYSTEMTIME timeLocal;
								SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &timeUTC, &timeLocal);
								otime = COleDateTime(timeLocal);
							}

							SYSTEMTIME systime;
							otime.GetAsSystemTime(systime);
							fileTime = CTime(systime);
						}
					}
					break;

				case DURATION:
					if (cs.Find(_TCHAR('m'))<0 && cs.Find(_TCHAR(':'))<0)
						iFileDuration = _ttoi(cs);
					break;

				default:	// case NONE: 와 동일
					{
						CString csBuf(cBuf);
						int colon = csBuf.Find(_T(":"));
						CString csLeft = csBuf.Left(colon);
						csLeft.MakeUpper();
						if ((csLeft.Find(_T("FORMAT"))>=0) && 
							(csLeft.Find(_T("EXTENSIONS"))>=0) && 
							(csLeft.Find(_T("USUALLY"))>=0) &&
							(csLeft.Find(_T("USED"))>=0)) {
								csBuf.Delete(0, colon+1);
								CSmallUtilz4iTrans::tokenize2CSA(static_cast<LPCTSTR>(csBuf), csaExtList);
						}
					}
				}
			}

			continue;
			
		case 2:
			{
				static LPCSTR videoInfoNames[] = {
					"Format settings, ReFrames  ",	"ID  ",	"Stream identifier  ",	"StreamOrder  ",	"Codec ID  ",
					"Duration  ",	"Format  ",	"Frame rate  ",	"Original frame rate  ",	"Frame rate mode  ",
					"Frame count  ",	"Width  ",	"Height  ",	"Rotation  ",
					"Delay  ",	"Bit rate  ",	"Maximum bit rate  ",	"Pixel aspect ratio  ",
					"Format settings, BVOP  ",	"Codec settings, BVOP  ",	"Format settings, QPel  ",	"Codec settings, QPel  ",
					"Format settings, GMC  ",	"Codec settings, GMC  ",	"Format settings, Matrix  ",	"Codec settings, Matrix  ",
					"Scan type  ",	"Interlacement  ",	"Format profile  ",	"Codec profile  ",
					"Stream size  ",	"Resolution  ",	"Bit depth  ",	"Title  "
				};
				enum VIDEOINFO {
					NONE,	REFRAMES,	ID,	STREAMID,	STREAMORDER, CODECID,	DURATION,
					FORMAT,	FRAMERATE,	ORIGINALFRAMERATE,	FRAMERATEMODE,	FRAMECOUNT,
					WIDTH,	HEIGHT,	ROTATION,	DELAY,	BITRATE,	MAXBITRATE,
					PIXELAR,	BVOP,	QPEL,	GMC,	MATRIX,
					INTERLACE,	CODECPROFILE,	STREAMSIZE,	BITDEPTH, TITLE
				};
				static enum VIDEOINFO videoInfos[] = {
					REFRAMES,	ID,	STREAMID,	STREAMORDER, CODECID,
					DURATION,	FORMAT,	FRAMERATE,	ORIGINALFRAMERATE,	FRAMERATEMODE,
					FRAMECOUNT,	WIDTH,	HEIGHT,	ROTATION,
					DELAY,	BITRATE,	MAXBITRATE,	PIXELAR,
					BVOP,	BVOP,	QPEL,	QPEL,
					GMC,	GMC,	MATRIX,	MATRIX,
					INTERLACE,	INTERLACE,	CODECPROFILE,	CODECPROFILE,
					STREAMSIZE,	BITDEPTH,	BITDEPTH,	TITLE
				};

				VIDEOINFO info = NONE;
				CString cs;
				for (int i=0; i<COUNTOF(videoInfos); i++) {
					if (compareNGetValue(cBuf, videoInfoNames[i], cs)) {
						info = videoInfos[i];
						break;
					}
				}

				switch (info) {
				case REFRAMES:
					if (cs.Find(_TCHAR('f'))<0)
						i264ReferenceFrames = _ttoi(cs);
					break;

				case ID:
					iVideoID = _ttoi(cs);
					break;

				case STREAMID:
					iVideoStreamID = _ttoi(cs);
					break;

				case STREAMORDER:
					iVideoStreamOrder = _ttoi(cs);
					break;

				case CODECID:
					{
						static LPCTSTR MPEGs[] = {
							_T("MPG4"),	_T("MP42"),	_T("MP43"),
							_T("DIV3"),	_T("DIV4"),	_T("DIV5")
						};
						static LPCTSTR WMVs[] = {
							_T("WMV1"),	_T("WMV2"),	_T("WMV3")
						};
						
						bool done=false;
						for (int i=0; i<COUNTOF(MPEGs); i++) {
							if (cs.Find(MPEGs[i]) >= 0) {
							//if (cs.Compare(MPEGs[i]) == 0) {
								iDIVxMPEG4 = i+1;
								done=true;
								break;
							}
						}
						if (done) break;

						for (int i=0; i<COUNTOF(WMVs); i++) {
							if (cs.Find(WMVs[i]) >= 0) {
							//if (cs.Compare(WMVs[i]) == 0) {
								vfVideoFormat = VFMT_WMV;
								done=true;
								break;
							}
						}
						if (done) break;

						if (cs.Compare(_T("WVC1")) == 0) vfVideoFormat = VFMT_VC1;
						else if (cs.Find(_T("VP7")) >= 0) vfVideoFormat = VFMT_VP7;
						else if (cs.Find(_T("VP8")) >= 0) vfVideoFormat = VFMT_VP8;
						else if ((cs.GetLength()==4) && (cs.Left(2).CompareNoCase(_T("rv")) == 0)
							&& _istdigit(cs.GetAt(2)) && _istdigit(cs.GetAt(3))) vfVideoFormat = VFMT_RM;
					}

					break;

				case DURATION:
					if (cs.Find(_TCHAR('m'))<0 && cs.Find(_TCHAR(':'))<0)
						iVideoDuration = _ttoi(cs);
					break;

				case FORMAT:
					if (
						(cs.Find(_T("AVC"))>=0) ||
						(cs.Find(_T("264"))>=0)
						) vfVideoFormat = VFMT_H264;
					else if (cs.Find(_T("263"))>=0)
						vfVideoFormat = VFMT_H263;
					else if (
						cs.Compare(_T("MPEG-4 Visual")) == 0 ||
						cs.CompareNoCase(_T("xvid")) == 0 ||
						cs.CompareNoCase(_T("divx")) == 0
						) vfVideoFormat = VFMT_MPEG4;
					else if (cs.Compare(_T("MPEG Video")) == 0)
						vfVideoFormat = VFMT_MPEG;
					else if (
						(cs.Compare(_T("WMV1")) == 0) ||
						(cs.Compare(_T("WMV2")) == 0) ||
						(cs.Compare(_T("WMV3")) == 0) ||
						(cs.Compare(_T("WVC1")) == 0) ||
						(cs.Compare(_T("VC-1")) == 0)
						) {
						// Do Nothing
						// WMV 계열은 Codec ID로 확인
					} else if (cs.CompareNoCase(_T("VP7")) == 0)
						vfVideoFormat = VFMT_VP7;
					else if (cs.CompareNoCase(_T("VP8")) == 0)
						vfVideoFormat = VFMT_VP8;
					else if (
						cs.CompareNoCase(_T("JPEG")) == 0 ||
						cs.CompareNoCase(_T("MJPG")) == 0	// 이런 경우는 없지만, 혹시나…
						)
						vfVideoFormat = VFMT_MJPEG;
					else if (
						cs.CompareNoCase(_T("VP6")) == 0
						)
						vfVideoFormat = VFMT_VP6;
					else if (
						cs.CompareNoCase(_T("Cinepack")) == 0 ||
						cs.CompareNoCase(_T("Cinepak")) == 0	// 언젠간 이렇게 바뀌지 않을까?
						)
						vfVideoFormat = VFMT_CINEPAK;
					else if (
						cs.CompareNoCase(_T("RLE")) == 0
						)
						vfVideoFormat = VFMT_RLE;
					else if ((cs.GetLength()==4) && (cs.Left(2).CompareNoCase(_T("rv")) == 0)
						&& _istdigit(cs.GetAt(2)) && _istdigit(cs.GetAt(3))) vfVideoFormat = VFMT_RM;
					else
						vfVideoFormat = VFMT_UNKNOWN;

					break;

				case FRAMERATE:
					csFPS = cs;
					csFPS.TrimRight(_T(" fps"));
					break;

				case ORIGINALFRAMERATE:
					csOriginalFPS = cs;
					csOriginalFPS.TrimRight(_T(" fps"));
					break;
					
				case FRAMERATEMODE:
					if (cs.GetAt(0) == _TCHAR('V'))
						bVFR = true;
					break;

				case FRAMECOUNT:
					iFrameCount = _ttoi(cs);
					break;

				case WIDTH:
					if (cs.Find(_TCHAR(' '))<0 && cs.Find(_TCHAR('p'))<0)
						iWidth = _ttoi(cs);
					break;

				case HEIGHT:
					if (cs.Find(_TCHAR(' '))<0 && cs.Find(_TCHAR('p'))<0)
						iHeight = _ttoi(cs);
					break;

				case ROTATION:
					if (cs.GetLength() && _istdigit(cs.GetAt(0)))
						iRotation = _ttoi(cs);
					break;

				case DELAY:
					GetTime(cs, iVideoDelay);
					break;

				case BITRATE:
					if (cs.Find(_TCHAR(' '))<0 && cs.Find(_TCHAR('p'))<0)
						iVideoBitRate = _ttoi(cs);
					break;

				case MAXBITRATE:
					if (cs.Find(_TCHAR(' '))<0 && cs.Find(_TCHAR('p'))<0)
						iVideoMaxBitRate = _ttoi(cs);
					break;

				case PIXELAR:
					{
						double dCS = _ttof(cs);
						if (dCS > DOUBLE_MIN_LIMIT) dPAR = dCS;
					}
					break;

				case BVOP:
					iMPEG4_BVOP = ((cs.CompareNoCase(_T("Yes")) == 0)||(cs.Compare(_T("2")) == 0))?2:1;
					break;

				case QPEL:
					iMPEG4_QPel = (cs.CompareNoCase(_T("Yes")) == 0)?2:1;
					break;

				case GMC:
					iMPEG4_GMC = _ttoi(cs);
					break;

				case MATRIX:
					iMPEG4_Matrix = (cs.Find(_T("H.263"))>=0)?1:2;
					break;

				case INTERLACE:
					if ((cs.CompareNoCase(_T("Progressive")) == 0) ||
						(cs.CompareNoCase(_T("PPF")) == 0)) {
						iInterlace = 0;
					} else if ((cs.Right(3).CompareNoCase(_T("AFF")) == 0) ||
						(cs.Compare(_T("TFF")) == 0) ||
						(cs.Compare(_T("BFF")) == 0) ||
						(cs.Compare(_T("Interlaced")) == 0)) {
						iInterlace = 1;
					}
					break;

				case CODECPROFILE:
					{
						int i = cs.Find(_T("@L"));
						if (i>0) {
							cs264Profile = cs;
							cs264Profile.Delete(0, i+2);
						}
					}
					break;

				case STREAMSIZE:
					{
						long long llRet = 0;
						bool bStop = false;
						
						for (int i=0; i<cs.GetLength(); i++) {
							TCHAR tc = cs.GetAt(i);
							if (!_istdigit(tc)) {
								bStop = true;
								break;
							}
							llRet = llRet*10 + (tc - _TCHAR('0'));
						}
						if (!bStop) llVideoSize = llRet;
					}
					break;

				case BITDEPTH:
					cs.TrimRight();
					if (cs.Right(5).Compare(_T(" bits")) == 0)
						iBitDepthV = _ttoi(cs);
					break;

				case TITLE:
					fixTitle(cs);
					csVideoTitle = cs;
					break;
				}
			}

			continue;

		case 3:
			{
				static LPCSTR audioInfoNames[] = {
					"ID  ",	"Stream identifier  ",	"StreamOrder  ",	"Format  ",	"Codec ID  ",
					"Delay  ",	"Duration  ",	"Bit rate  ",	"Format profile  ",
					"Language  ",	"Sampling rate  ",	"Channel", "Original Channel",
					"Bit depth  ",	"Stream size  ", "Title  "
				};
				enum AUDIOINFO {
					NONE,	ID,	STREAMID,	STREAMORDER, FORMAT,	CODECID,
					DELAY,	DURATION,	BITRATE,	FORMATPROFILE,
					LANGUAGE,	SAMPLERATE,	CHANNELS, ORIGINAL_CHANNELS,	BITDEPTH,
					STREAMSIZE, TITLE
				};
				static enum AUDIOINFO audioInfos[] = {
					ID,	STREAMID,	STREAMORDER, FORMAT,	CODECID,
					DELAY,	DURATION,	BITRATE,	FORMATPROFILE,
					LANGUAGE,	SAMPLERATE,	CHANNELS,	ORIGINAL_CHANNELS,
					BITDEPTH,	STREAMSIZE, TITLE
				};

				AUDIOINFO info = NONE;
				CString cs;
				for (int i=0; i<COUNTOF(audioInfos); i++) {
					if (compareNGetValue(cBuf, audioInfoNames[i], cs)) {
						info = audioInfos[i];
						break;
					}
				}

				switch (info) {
				case ID:
					iAudioID[iAudioPos] = _ttoi(cs);
					break;

				case STREAMID:
					iAudioStreamID[iAudioPos] = _ttoi(cs);
					break;

				case STREAMORDER:
					iAudioStreamOrder[iAudioPos] = _ttoi(cs);
					break;
					
				case FORMAT:
					{
						if (cs.Compare(_T("PCM")) == 0) {
							if (afAudioFormat[iAudioPos] != AFMT_TWOS)
								afAudioFormat[iAudioPos] = AFMT_PCM;
						} else {
							static LPCTSTR audioFormatNames[] = {
								_T("AAC"),	_T("DTS"),	_T("AC-3"),	_T("MPEG Audio"),
								_T("Vorbis"),	_T("WMA"),	_T("ADPCM"),	_T("FLAC"),
								_T("Cooker")
							};
							static AudioFormat audioFormatValues[] = {
								AFMT_AAC,	AFMT_DTS,	AFMT_AC3,	AFMT_MP3,
								AFMT_OGG,	AFMT_WMA,	AFMT_PCM,	AFMT_FLAC,
								AFMT_RM
							};
							
							afAudioFormat[iAudioPos] = AFMT_UNKNOWN;
							for (int i=0; i<COUNTOF(audioFormatValues); i++) {
								if (cs.Compare(audioFormatNames[i]) == 0)
									afAudioFormat[iAudioPos] = audioFormatValues[i];
							}
						}
					}

					break;
					
				case CODECID:
					{
						static LPCTSTR audioCodecIDs[] = {
							_T("twos"),	_T("DTS"),	_T("raac"),	_T("racp"),
							_T("lpcJ"),	_T("14_4"),	_T("28_8"),	_T("dnet"),
							_T("sipr"),	_T("cook"),	_T("atrc"),	_T("raac"),
							_T("racp"),	_T("ralf")
						};

						static AudioFormat audioFormatValues[] = {
							AFMT_TWOS,	AFMT_DTS,	AFMT_AAC,	AFMT_AAC,
							AFMT_RM,	AFMT_RM,	AFMT_RM,	AFMT_AC3,
							AFMT_RM,	AFMT_RM,	AFMT_RM,	AFMT_AAC,
							AFMT_AAC,	AFMT_RM
						};

						for (int i=0; i<COUNTOF(audioFormatValues); i++) {
							if (cs.CompareNoCase(audioCodecIDs[i]) == 0)
								afAudioFormat[iAudioPos] = audioFormatValues[i];
						}

						if (cs.Right(3).CompareNoCase(_T("AC3")) == 0)
							afAudioFormat[iAudioPos] = AFMT_AC3;
					}
					break;
					
				case DELAY:
					GetTime(cs, iAudioDelay[iAudioPos]);
					break;
					
				case DURATION:
					if (cs.Find(_TCHAR('m'))<0 && cs.Find(_TCHAR(':'))<0)
						iAudioDuration[iAudioPos] = _ttoi(cs);
					break;
					
				case BITRATE:
					if (cs.Find(_TCHAR(' '))<0 && cs.Find(_TCHAR('s'))<0)
						iBitRate[iAudioPos] = _ttoi(cs);
					break;
				
				case FORMATPROFILE:
					if (cs.Compare(_T("LC")) == 0)
						bProfileIsLC[iAudioPos] = true;
					break;
				
				case LANGUAGE:
					if (cs.GetLength()==2)
						_tcscpy_s(tcAudioLang+iAudioPos*3, 3, static_cast<LPCTSTR>(cs));
					break;
				
				case SAMPLERATE:
					if (cs.Find(_TCHAR(' '))<0 && cs.Find(_TCHAR('H'))<0)
						iSamplingRate[iAudioPos] = _ttoi(cs);
					break;
				
				case CHANNELS:
					// Channel로 시작하면 무조건 채널 정보 읽는 걸로 변경 (2013.7.28)
					// 숫자로만 되어있거나 숫자+channels로만 되어있는 경우만 인식
					// Front: L C R, 등등 또는 3/2/0.1 등의 포맷은 개무시
					if (cs.FindOneOf(_T(":,/"))<0) {
						if (cs.Right(8).CompareNoCase(_T("channels")) == 0) {
							cs = cs.Left(cs.GetLength()-8);
							cs.TrimRight();
						}

						if (cs.GetLength()<3 && _istdigit(LPCTSTR(cs)[0])) {
							int audioChannels = _ttoi(cs);
							if (audioChannels>0) iChannels[iAudioPos] = audioChannels;
						}
					}

					break;

				case ORIGINAL_CHANNELS:
					// 위의 case CHANNELS: 코드를 그대로 사용
					if (cs.FindOneOf(_T(":,/"))<0) {
						if (cs.Right(8).CompareNoCase(_T("channels")) == 0) {
							cs = cs.Left(cs.GetLength()-8);
							cs.TrimRight();
						}

						if (cs.GetLength()<3 && _istdigit(LPCTSTR(cs)[0])) {
							int audioChannels = _ttoi(cs);
							if (audioChannels>0) iOriginalChannelCount[iAudioPos] = audioChannels;
						}
					}

					break;
				
				case BITDEPTH:
					if (cs.Find(_TCHAR(' '))<0 && cs.Find(_TCHAR('b'))<0)
						iBitDepthA[iAudioPos] = _ttoi(cs);
					break;
				
				case STREAMSIZE:
					{
						long long llRet = 0;
						bool bStop = false;
						
						for (int i=0; i<cs.GetLength(); i++) {
							TCHAR tc = cs.GetAt(i);
							if (!_istdigit(tc)) {
								bStop = true;
								break;
							}
							llRet = llRet*10 + (tc - _TCHAR('0'));
						}
						
						if (!bStop) llAudioSize = llRet;
					}
					break;

				case TITLE:
					fixTitle(cs);
					csAudioTitle[iAudioPos] = cs;
					break;
				}
			}
			
			continue;
			
		case 4:
			{
				static LPCSTR textInfoNames[] = {
					"ID  ",	"Stream identifier  ",	"StreamOrder  ",	"Format  ",	"Language  ",
					"Muxing mode  ",	"Delay  ",	"Title  "
				};
				enum TEXTINFO { 
					NONE,	ID,	STREAMID,	STREAMORDER, FORMAT,	LANGUAGE,	MUXINGMODE, DELAY, TITLE
				};
				static enum TEXTINFO textInfos[] = {
					ID,	STREAMID,	STREAMORDER, FORMAT,	LANGUAGE,
					MUXINGMODE, DELAY, TITLE
				};
				
				TEXTINFO info = NONE;
				CString cs;
				for (int i=0; i<COUNTOF(textInfos); i++) {
					if (compareNGetValue(cBuf, textInfoNames[i], cs)) {
						info = textInfos[i];
						break;
					}
				}

				switch (info) {
				case ID:
					iSubID[iSubPos] = _ttoi(cs);
					break;

				case STREAMID:
					iSubStreamID[iSubPos] = _ttoi(cs);
					break;

				case STREAMORDER:
					iSubStreamOrder[iSubPos] = _ttoi(cs);
					break;

				case FORMAT:
					{
						if ((cs.Find(_T("UTF"))>=0) && (cs.Find(_TCHAR('8'))>=0))
							sfSubFormat[iSubPos] = SFMT_SRT;
						else {
							sfSubFormat[iSubPos] = SFMT_UNKNOWN;

							static LPCTSTR subFormatNames[] = {
								_T("Timed text"),	_T("ASS"),	_T("SSA")
							};
							static SubFormat subFormatValues[] = {
								SFMT_TTXT,	SFMT_ASS,	SFMT_ASS
							};

							for (int i=0; i<COUNTOF(subFormatValues); i++) {
								if (cs.CompareNoCase(subFormatNames[i]) == 0)
									sfSubFormat[iSubPos] = subFormatValues[i];
							}
						}
					}

					break;

				case LANGUAGE:
					if (cs.GetLength()==2)
						_tcscpy_s(tcSubLang+iSubPos*3, 3, static_cast<LPCTSTR>(cs));
					break;

				case MUXINGMODE:
					if (cs.Compare(_T("sbtl")) == 0)
						bMuxingModeSbtl[iSubPos] = true;
					break;

				case DELAY:
					GetTime(cs, iSubDelay[iSubPos]);
					break;

				case TITLE:
					fixTitle(cs);
					csSubTitle[iSubPos] = cs;
					break;
				}

			}
			
			continue;
			
		case 5:
			{
				static LPCSTR menuInfoNames[] = {
					"ID  ",	"StreamOrder  ",	"Format  "
				};
				enum MENUINFO { 
					NONE,	ID,	STREAMORDER, FORMAT
				};
				static enum MENUINFO menuInfos[] = {
					ID,	STREAMORDER,	FORMAT
				};

				MENUINFO info = NONE;
				CString cs;
				for (int i=0; i<COUNTOF(menuInfos); i++) {
					if (compareNGetValue(cBuf, menuInfoNames[i], cs)) {
						info = menuInfos[i];
						break;
					}
				}

				switch (info) {
				case ID:
					iMenuID = _ttoi(cs);
					break;

				case STREAMORDER:
					iMenuStreamOrder = _ttoi(cs);
					break;

				case FORMAT:
					if (cs.CompareNoCase(_T("Timed text")) == 0)
						sfMenuFormat = SFMT_TTXT;
					break;

				default:
					{
						CString s(cBuf);
						if (s.GetLength()<14) break;
						CString sTime = s.Left(13);
						// 00:00:00.000
						// 0123456789012
						if ((sTime.GetAt(2) != _TCHAR(':')) ||
							(sTime.GetAt(5) != _TCHAR(':')) || 
							((sTime.GetAt(8) != _TCHAR('.')) && (sTime.GetAt(8) != _TCHAR(','))) || // 이런 일은 없겠지만
							(sTime.GetAt(12) != _TCHAR(' '))) continue;

						sTime.TrimRight();
						sTime.Delete(8);
						sTime.Delete(5);
						sTime.Delete(2);

						// 000000000
						// 012345678

						if (sTime.GetLength()!=9) break;
						for (int i=0; i<9; i++) {
							if (!_istdigit(sTime.GetAt(i))) break;
						}

						// 여기까지 왔으면 챕터에 추가 대상
						s.Delete(0, 12);
						s.TrimLeft();
						s.TrimLeft(_TCHAR(':'));
						s.TrimLeft();
						s.TrimRight();

						s = sTime+s;

						csaChapters.Add(s);
					}
				}
			}
			
			continue;
		}
	}
	fclose(f);
	
	if (iKeepTempFiles<2)
		CSmallUtilz4iTrans::DeleteSomeFile(csMediaInfoResult, iKeepTempFiles==1);

	// Frame rate은 없고, Original frame rate만 있을 때는
	// Original frame rate를 Frame rate에 덮어씀
	if (csFPS.IsEmpty()) csFPS = csOriginalFPS;

	// 우선순위는 큰 게 장땡 / ko 80, en 70, ja 60, de 50, fr 40, ru 30, **(else) 20 / 단, 일치하면 90
	// aac 7 - dts 6 - wav 5 - ac3 4 - mp2/3 3 - ogg 2 - WMA 1
	
	if (iVideoStreamOrder<0) iVideoStreamOrder = iVideoStreamID;
	if (iVideoStreamOrder<0) iVideoStreamOrder = 0;

	for (int i=0; i<iAudioCount; i++) {
		if (iAudioStreamOrder[i]<0) iAudioStreamOrder[i] = iAudioStreamID[i];
		if (iAudioStreamOrder[i]<0) iAudioStreamOrder[i] = 0;

		if (lpAudioCountry) {
			static LPCTSTR lan[] = {
				_T("ko"),	_T("en"),	_T("ja"),
				_T("de"),	_T("fr"),	_T("ru")
			};
			TCHAR *tc0 = tcAudioLang+i*3;
			TCHAR *tc1 = tc0+1;
			
			iAudioWeight[i] = 20;
			for (int j=0; j<COUNTOF(lan); j++) {
				if (_tcsncmp(tc0, lan[i], 2) == 0) iAudioWeight[i] = 80-(j*10);
			}
			if (iAudioWeight[i] == 20) {
				if (lpAudioCountry[0] == _TCHAR('*') && lpAudioCountry[1] == _TCHAR('*')) iAudioWeight[i] = 90;
			}
			if ((*tc0 == lpAudioCountry[0]) && (*tc1 == lpAudioCountry[1])) iAudioWeight[i] = 90;
		}
		
		static enum AudioFormat aformat[] = {
			AFMT_AAC,	AFMT_PCM,	AFMT_FLAC,	AFMT_DTS,
			AFMT_AC3,	AFMT_MP3,	AFMT_OGG,	AFMT_WMA
		};
		for (int j=0; j<COUNTOF(aformat); j++) {
			if (afAudioFormat[i] == aformat[j])
				iAudioWeight[i] += (8-j);
		}

		// channel count 정리
		// 컨테이너에서 리포트한 개수와 진짜 개수가 다른 경우 처리
		if (iOriginalChannelCount[i]>0) iChannels[i] = iOriginalChannelCount[i];
	}
	
	for (int i=0; i<iSubCount; i++) {
		if (iSubStreamOrder[i]<0) iSubStreamOrder[i] = iSubStreamID[i];
		if (iSubStreamOrder[i]<0) iSubStreamOrder[i] = 0;
	}

	// FFMpeg용 Batch file 생성 (csBatch)

	lpAppLong = static_cast<LPCTSTR>(csFFMpegLongExe);
	lpAppLongName = CSmallUtilz4iTrans::getAppNameOnly(lpAppLong);

	if (_tfopen_s(&f, csBatch, _T("wt")) || !f) return;

	csParam.Format(_T("-i \"%s\""), lpFilename);

	cs.Format(_T("\"%s\" %s\n"), static_cast<LPCTSTR>(csFFMpegExe), static_cast<LPCTSTR>(csParam));

	printfuni2ansi(f, static_cast<LPCTSTR>(cs));

	fclose(f);

	// 실행
	csaAppNames.RemoveAll();
	csaAppNames.Add(lpAppLongName);
	redir = new CRedirect(csBatch, csaAppNames, NULL, NULL, NULL, -1, csFFMpegResult);
	redir->Run();

	// Batch file 삭제
	if (iKeepTempFiles<2)
		CSmallUtilz4iTrans::DeleteSomeFile(csBatch, iKeepTempFiles==1);
	
	delete redir;
	redir = NULL;


// 	Stream #0:0(eng): Video: h264 (High), yuv420p, 1280x534 [SAR 1:1 DAR 640:267], 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc
//  Metadata:
//    title           : x264
//  Stream #0:1(eng): Audio: dts (DTS), 48000 Hz, 5.1(side), fltp, 1536 kb/s (default)
//  Metadata:
//    title           : DTS 5.1
//  Stream #0:2: Audio: vorbis, 48000 Hz, stereo, fltp
//  Metadata:
//    title           : Commentary
//  Stream #0:3(eng): Subtitle: subrip (default)
//  Stream #0:4(bul): Subtitle: subrip
//  Stream #0:5(chi): Subtitle: subrip

	// MP4 파일에 메뉴가 포함된 경우 이 과정을 통해 iSubStreamOrder[]가 좀 깨짐
	// 챕터와 자막을 제대로 구분하는 부분이 없기 때문
	// 하지만, MP4는 ID로 읽기 때문에 아무런 문제가 없음.
	{
		size = CSmallUtilz4iTrans::GetFileSize(csFFMpegResult);

		int curaudio = 0;
		int cursub = 0;
		bool bIamInSubtitle = false;

		if (_tfopen_s(&f, csFFMpegResult, _T("rt")) || !f) return;
		while (size && !feof(f)) {
			if (fgets(cBuf, MAX_PATH, f) == NULL) break;

			// 일단 문자열 내에서 "Stream #0:" 찾기
			char *cBuf2 = cBuf;
			while (isspace_char(*cBuf2)) cBuf2++;
			if (strncmp(cBuf2, "Stream #0:", 10)) {
				if (!bIamInSubtitle) continue;
				if (strncmp(cBuf2, "handler_name ", 13)) continue;
				int len = strlen(cBuf2);
				bool bFound = false;
				for (int i=13; i<len; i++) {
					if (strncmp(cBuf2+i, ":chap", 5) == 0) {
						bFound = true;
						break;
					}
				}
				if (bFound && cursub>0) {
					iMenuStreamOrder = iSubStreamOrder[--cursub];
				}
				bIamInSubtitle = false;
				continue;
			}
			cBuf2+=10;

			if (!isdigit_char(*cBuf2)) continue;
			int trackorder = atoi(cBuf2);

			while ((*cBuf2) && (*cBuf2 != ':')) cBuf2++;
			if (!(*cBuf2)) continue;
			cBuf2++;

			while (isspace_char(*cBuf2)) cBuf2++;

			bIamInSubtitle = false;
			switch (*cBuf2) {
			case 'V':
			case 'v':
				iVideoStreamOrder = trackorder;
				break;

			case 'A':
			case 'a':
				iAudioStreamOrder[curaudio++] = trackorder;
				break;

			case 'S':
			case 's':
				iSubStreamOrder[cursub++] = trackorder;
				bIamInSubtitle = true;
				break;
			}
		}

		fclose(f);
	}

	if (iKeepTempFiles<2)
		CSmallUtilz4iTrans::DeleteSomeFile(csFFMpegResult, iKeepTempFiles==1);

	// MP4 파일의 경우 자막에 챕터 정보가 섞인 경우가 있어
	// 후처리 실시 필요
	
	iSubCountSbtlOnly = iSubCount;
	if (ffFileFormat == FFMT_MP4) {
		for (int i=0; i<iSubCount; i++) {
			if (!bMuxingModeSbtl[i]) {
				iSubCountSbtlOnly--;
				iSubChapterID = iSubID[i];
			}
		}
		if ((iMenuID>=0) && (sfMenuFormat == SFMT_TTXT)) iSubChapterID = iMenuID;
	} else {
		for (int i=0; i<iSubCount; i++) {
			bMuxingModeSbtl[i] = true;
		}
	}
	
	if (csaChapters.GetSize()) iChapter = 1;
	else if (iSubChapterID >= 0) iChapter = 2;
	
	// iChapter가 2인 경우는 아직 챕터 정보는 없음
	// 이 점을 명심할 것

	// 권장 확장자 목록 추가
	switch (ffFileFormat)
	{
	case FFMT_AVI:
	case FFMT_DIVX:
		csaExtList.Add(_T("divx"));
		break;

	case FFMT_OGG:
		csaExtList.Add(_T("ogg"));
		csaExtList.Add(_T("ogm"));
		break;

	case FFMT_MP4:
		csaExtList.Add(_T("mov"));
		break;

	case FFMT_MPGPS:
		csaExtList.Add(_T("dat"));
		csaExtList.Add(_T("ts"));
		csaExtList.Add(_T("tp"));
		break;
	}

	// Video에 duration이 없는데, file에는 있는 경우 처리
	if (iVideoDuration <= 0) iVideoDuration = iFileDuration;
}

void CMediaInfo::printfuni2ansi(FILE *f, const TCHAR *tc)
{
	CT2A c(tc);
	fprintf(f, "%s", c);
}

void CMediaInfo::GetValue(CString &cs)
{
	int i=cs.Find(_TCHAR(':'));
	cs.Delete(0, i+1);
	cs.TrimLeft();
	cs.TrimRight();
}

bool CMediaInfo::GetTime(CString &cs, int &iTime)
{
	// 00:00:00.000
	// 012345678901
	// -00:00:00.000

	if (cs.GetLength()<12) return false;

	int iSign = 1;
	if (cs.GetAt(0) == _TCHAR('-')) {
		cs.Delete(0, 1);
		iSign = -1;
	}
	if (cs.GetLength()!=12) return false;
	if (
		(cs.GetAt(2) != _TCHAR(':')) ||
		(cs.GetAt(5) != _TCHAR(':')) ||
		(cs.GetAt(8) != _TCHAR('.'))
		)
		return false;
	
	CString csNew(_T(""));
	for (int i=0; i<12; i++) {
		TCHAR tc = cs.GetAt(i);
		if (_istdigit(tc))
			csNew += tc;
	}
	
	if (csNew.GetLength()!=9) return false;
	
	iTime = iSign * CSmallUtilz4iTrans::tcTime2Int(const_cast<LPTSTR>(static_cast<LPCTSTR>(csNew)), false);
	return true;
}

static int DecodeMimeBase64[80] = {
	62,-1,-1,-1,63,
	52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
	-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
	15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
	-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
	41,42,43,44,45,46,47,48,49,50,51
};

bool CMediaInfo::base64Decode(LPCTSTR lpStr, LPCTSTR lpFilename)
{
	const TCHAR* cp;
	int space_idx = 0, phase;
	int prev_d = 0;
	unsigned char c;
	
    space_idx = 0;
    phase = 0;
	
	int numBytes = _tcslen(lpStr);
	if (!numBytes) return false;
	
	unsigned char *dst = new unsigned char[numBytes];
	if (!dst) return false;
	
    for ( cp = lpStr; *cp != _TCHAR('\0'); ++cp ) {
		int ii = int(*cp);
		int d = (ii>=43 && ii<123)?DecodeMimeBase64[ii-43]:-1;
        if ( d != -1 ) {
            switch ( phase ) {
			case 0:
				++phase;
				break;
			case 1:
				c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) );
				if ( space_idx < numBytes )
					dst[space_idx++] = c;
				++phase;
				break;
			case 2:
				c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) );
				if ( space_idx < numBytes )
					dst[space_idx++] = c;
				++phase;
				break;
			case 3:
				c = ( ( ( prev_d & 0x03 ) << 6 ) | d );
				if ( space_idx < numBytes )
					dst[space_idx++] = c;
				phase = 0;
				break;
            }
            prev_d = d;
        }
    }
	
	numBytes = space_idx;
	if (numBytes) {
		FILE *f;
		if (!_tfopen_s(&f, lpFilename, _T("wb")) && f) {
			fwrite(dst, 1, numBytes, f);
			fclose(f);
		}
		delete []dst;
		return true;
	}
	
	delete []dst;
	return false;
}

void CMediaInfo::initValues()
{
	ffFileFormat = FFMT_NONE;
	iFileSizeInMB = 0;
	
	vfVideoFormat = VFMT_NONE;
	csFPS = _T("");
	cs264Profile = _T("");
	i264ReferenceFrames = 0;
	
	iVideoID = -1;
	iVideoStreamOrder = -1;
	iVideoDelay = 0;
	iFileDuration = 0;
	iVideoDuration = 0;
	iWidth = 0;
	iHeight = 0;
	iRotation = 0;
	iOverallBitRate = 0;
	iVideoBitRate = 0;
	iVideoMaxBitRate = 0;
	iBitDepthV = -1;
	iFrameCount = 0;
	iDIVxMPEG4 = 0;
	dPAR = -100.0;
	
	iMPEG4_BVOP = 0;
	iMPEG4_QPel = 0;
	iMPEG4_GMC = 0;
	iMPEG4_Matrix = 0;
	iInterlace = -1;
	bVFR = false;
	
	iAudioCount = 0;
	iSubCount = 0;
	iSubCountSbtlOnly = 0;
	iSubChapterID = -1;
	iChapter = 0;
	csaChapters.RemoveAll();
	for (int i=0; i<MAXAUDSUBCOUNT; i++) {
		iAudioID[i] = -1;
		iAudioStreamOrder[i] = -1;
		iAudioDelay[i] = 0;
		afAudioFormat[i] = AFMT_NONE;
		iAudioDuration[i] = 0;
		iBitRate[i] = 0;
		bProfileIsLC[i] = false;
		iAudioWeight[i] = 0;
		
		iSamplingRate[i] = 44000;
		iChannels[i] = 1;
		iBitDepthA[i] = 8;
		
		iSubID[i] = -1;
		iSubStreamOrder[i] = -1;
		sfSubFormat[i] = SFMT_NONE;
		bMuxingModeSbtl[i] = false;
		iSubDelay[i] = 0;
	}
	ZeroMemory(tcAudioLang, sizeof(TCHAR)*MAXAUDSUBCOUNT*3);
	ZeroMemory(tcSubLang, sizeof(TCHAR)*MAXAUDSUBCOUNT*3);
	
	llVideoSize = 0;
	llAudioSize = 0;

	// Title 관련 초기화
	csVideoTitle = _T("");
	for (int i=0; i<MAXAUDSUBCOUNT; i++) {
		csAudioTitle[i] = _T("");
		csSubTitle[i] = _T("");
	}
}

static AudioFormat audioFormatValues[] = {
	AFMT_AAC,	AFMT_DTS,	AFMT_AC3,	AFMT_MP3,
	AFMT_OGG,	AFMT_PCM,	AFMT_WMA,	AFMT_FLAC,
	AFMT_TWOS,	AFMT_RM
};

void CMediaInfo::getDefaultAudioExt(AudioFormat af, LPCTSTR &lpExt)
{
	static LPCTSTR audioDefaultExts[] = {
		_T("aac"),	_T("dts"),	_T("ac3"),	_T("mp3"),
		_T("ogg"),	_T("wav"),	_T("wma"),	_T("flac"),
		_T("wav"),	_T("ra")
	};

	lpExt = _T("");
	for (int i=0; i<COUNTOF(audioFormatValues); i++) {
		if (audioFormatValues[i] == af) {
			lpExt = audioDefaultExts[i];
			break;
		}
	}
}

void CMediaInfo::getAudioType(AudioFormat af, LPCTSTR &lpType)
{
	static LPCTSTR audioFormatStrs[] = {
		_T("AAC"),	_T("DTS"),	_T("AC3"),	_T("MP3"),
		_T("OGG"),	_T("PCM"),	_T("WMA"),	_T("FLAC"),
		_T("TWOS"),	_T("RA")
	};

	lpType = _T("");
	for (int i=0; i<COUNTOF(audioFormatValues); i++) {
		if (audioFormatValues[i] == af) {
			lpType = audioFormatStrs[i];
			break;
		}
	}
}

void CMediaInfo::getDefaultContainerType(FileFormat ff, LPCTSTR &lpType)
{
	static FileFormat fileFormatValues[] = {
		FFMT_AVI,	FFMT_DIVX,	FFMT_MKV,	FFMT_FLV,
		FFMT_OGG,	FFMT_MP4,	FFMT_MPGPS,	FFMT_WMV,
		FFMT_SWF,	FFMT_QT,	FFMT_WEBM,	FFMT_RM,
		FFMT_MPGTS,	FFMT_BLURAY
	};

	static LPCTSTR fileFormatStrs[] = {
		_T("AVI"),	_T("DivX"),	_T("MKV"),	_T("FLV"),
		_T("OGM"),	_T("MP4"),	_T("MPEG"),	_T("WMV"),
		_T("SWF"),	_T("QT"),	_T("WebM"),	_T("RM"),
		_T("TS"),	_T("BluRay")
	};

	lpType = _T("");
	for (int i=0; i<COUNTOF(fileFormatValues); i++) {
		if (fileFormatValues[i] == ff) {
			lpType = fileFormatStrs[i];
			break;
		}
	}
}

void CMediaInfo::fixTitle(CString &cs)
{
	cs.Replace(_T("\""), _T(""));
	cs.Replace(_T("\\"), _T(""));
	cs.Replace(_T("\'"), _T(""));
	cs.Trim();

	CT2A aTitle(static_cast<LPCTSTR>(cs));
	CA2T tTitle(aTitle);

	cs = tTitle;

	// Imported with GPAC 0.4.6-DEV (internal rev. 7) 등의 문구가 나오면 지워버리기로 함 (2013.11.25)
	if (cs.Left(14).CompareNoCase(_T("Imported with ")) == 0) cs = _T("");
}